﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using lib_nrf24lu1_RF;
using System.Timers;          // Library for RFUSB functions

namespace Send_RF
{
    class RfUsb
    {
        //*******************************************************************
        //      RF variables
        //*******************************************************************
        public lib_nrf24lu1_RF.BzirfManager2 bzirf;     // Instance for controlling RFUSB
        private byte[] rf_packet = new byte[10];        // Byte for storing data to transmit/receive 
        private bool isActive;

        //*******************************************************************
        //      RF protocol commands
        //*******************************************************************
        public byte CMD_RF_ON = 0xAA;           // Commands for controlling RFUSB
        public byte CMD_RF_OFF = 0xBB;
        public byte CMD_SEND_RF = 0xFF;
        public byte CMD_DATA_RECEIVED = 0xCC;

        //*******************************************************************
        //      Moways Registration:
        //*******************************************************************
        private List<Moway> mowayList;

        private int[,][] matrixTest = new int[SendForm.SIZE_MOWAYS,SendForm.SIZE_TEST][];
        private int seqNRcv = 0;
        private bool _ack = false;

        public RfUsb()
        {
            this.bzirf = new BzirfManager2();
            this.bzirf.Read += new NewBziRFDataEventHandler(bziRFReadEventDistance);     // Definition of an event, thrown when RFUSB receives data

            this.bzirf.InitUsb();
            this.bzirf.RegisterHidNotification();

            this.mowayList = new List<Moway>();
        }

        //*******************************************************************
        //      Stop RFUSB
        //*******************************************************************
        public void turnOff()
        {
            this.rf_packet[0] = CMD_RF_OFF;
            this.bzirf.Send(this.rf_packet);
            this.isActive = false;
        }

        //*******************************************************************
        //      Start RFUSB (MowayGUI must be closed to prevent conflicts
        //************************************  *******************************
        public void TurnOn()
        {
            this.TurnOn(0, 1);
        }
        public void TurnOn(int channel, int selfAddress)
        {
            // Check if RFUSB is conected
            if (bzirf.USBdongleconected == true)
            {
                if (!bzirf.RFIsRunning())
                {
                    // Activate RFUSB
                    if (bzirf.Start((byte)channel, (byte)selfAddress))
                    {
                        System.Diagnostics.Debug.WriteLine("-LOG- Turning On RFUSB. -LOG-");
                        rf_packet[0] = CMD_RF_ON;
                        rf_packet[1] = Convert.ToByte(channel);    // RFUSB direction (LSByte)
                        rf_packet[2] = Convert.ToByte(selfAddress);
                        bzirf.Send(rf_packet);
                        
                    }
                    else
                    {
                        System.Diagnostics.Debug.WriteLine("-ERROR- RFUSB can´t start. Close other programs that can be using RFUSB and restart the application. -ERROR-");
                    }
                }
                this.isActive = true;
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("-ERROR- RFUSB disconnected -ERROR-");
            }
        }

        public bool Active()
        {
            return this.isActive;
        }

        public bool Ack
        {
            get { return this._ack; }
        }

        public int SizeConvoy()
        {
            return this.mowayList.Count();
        }

        public IEnumerator<Moway> getMowaysIterator()
        {
            System.Diagnostics.Debug.WriteLine("-LOG- Retrieving Moways List. -LOG-");
                this.updateList();
                Moway[] newArray = new Moway[mowayList.Count];
                this.mowayList.CopyTo(newArray);
                return ((IEnumerable<Moway>)newArray).GetEnumerator();
        }


        //*******************************************************************
        //     Send a packet containing 10 bytes tops
        //*******************************************************************

        //Broadcast to all moways in list.
        public void Send(byte[] data)
        {
            try
            {
                this.auxSend(data);
                System.Diagnostics.Debug.WriteLine("-LOG- Broadcasting Dara -LOG-");
                foreach (Moway m in this.mowayList)
                {
                    this.rf_packet[1] = Convert.ToByte(m.Id);
                    bzirf.Send(this.rf_packet);
                    this.printPacket(this.rf_packet);
                }
            }catch(Exception e)
            {
                return;
            }
            
        }

        //Building the packet
        private void auxSend(byte[] data)
        {
            // Send command + moway address + 1 byte of data
            //rf_packet[0] = CMD_SEND_RF;
            //rf_packet[1] = Convert.ToByte(2);    // Moway address 
            //rf_packet[2] = Convert.ToByte(25);            // Data 0
            this.clearRfData();
            this.rf_packet[0] = CMD_SEND_RF;
            int i;
            for (i = 0; i < data.Length; i++)
            {
                this.rf_packet[i + 2] = data[i];
            }
            this._ack = false;
        }

        //Directional Delivery
        public void Send(int mowayAddress, byte[] data)
        {
            System.Diagnostics.Debug.WriteLine("-LOG- Sending to a DIR -LOG-");
            this.auxSend(data);
            this.rf_packet[1] = Convert.ToByte(mowayAddress);
            bzirf.Send(this.rf_packet);
            this.printPacket(this.rf_packet);
        }

        //*******************************************************************
        //      Data reception
        //*******************************************************************
        private void bziRFReadEvent(NewBziRFDataEventArgs e)
        {
            int idMoway = Convert.ToInt32(e.newdata[0].ToString());
            int spd = Convert.ToInt32(e.newdata[1].ToString());
            int battery = Convert.ToInt32(e.newdata[2].ToString());
            int snsL = Convert.ToInt32(e.newdata[2].ToString());
            int snsR = Convert.ToInt32(e.newdata[3].ToString());
            int lnL = Convert.ToInt32(e.newdata[4].ToString());
            int lnR = Convert.ToInt32(e.newdata[5].ToString());

            Moway toAdd = this.mowayList.Find(x => x.Id == idMoway);
            if( toAdd == null)
            {
                this.mowayList.Add(new Moway(idMoway, spd, battery));
                System.Diagnostics.Debug.WriteLine("-LOG- Adding MOWAY "+mowayList.LastOrDefault()+" to list. -LOG-");
            }else{

                toAdd.updateData(spd,battery,System.DateTime.Now.Ticks);
            }

            this.printMowayList();

            
            //We have to define what happens in the reception. Where to log it
            //And which data are used. Future!
            //Also register the moways. Stop->SendRegistration->W8 2 secs -> Go!

        }

        private void bziRFReadEventTest(NewBziRFDataEventArgs e)
        {
            int ticks = Environment.TickCount;
            int idMoway = Convert.ToInt32(e.newdata[0].ToString());
            int rfMsg = Convert.ToInt32(e.newdata[1].ToString());
            int seqNumber = Convert.ToInt32(e.newdata[2].ToString());
            System.Diagnostics.Debug.WriteLine(idMoway+"<-");
            this.matrixTest[idMoway-27, seqNumber] = new int[] { rfMsg, ticks, seqNRcv++ };
            this._ack = true;
            
        }

        private void bziRFReadEventDistance(NewBziRFDataEventArgs e) 
        {
            
            int idMoway = Convert.ToInt32(e.newdata[0].ToString());
            int dist = Convert.ToInt32(e.newdata[01].ToString());
            int distM = Convert.ToInt32(e.newdata[2].ToString());
            System.Diagnostics.Debug.WriteLine((255*distM+dist).ToString());
        }

        public int[,][] DataTest()
        {
            return this.matrixTest;
        }

        public void resetMatrix()
        {
            this.seqNRcv = 0;
            for (int i = 0; i < this.matrixTest.GetLength(0); i++)
            {
                for(int j = 0; j < this.matrixTest.GetLength(1); j++)
                {
                    this.matrixTest[i,j] = new int[] { 0, 0, 0 };
                }
            }
        }


        //*******************************************************************
        //      Clears the byteArray
        //*******************************************************************
        private void clearRfData()
        {
            for (int i = 0; i < this.rf_packet.Length; i++ )
            {
                this.rf_packet[i] = Convert.ToByte(0);
            }
        }

        //*******************************************************************
        //      Logs information about packet being sent
        //*******************************************************************
        private void printPacket(byte[] packet)
        {
            String log = DateTime.Now.ToString("HH:mm:ss tt") + " -> [";
            foreach (byte b in packet)
            {
                log += b.ToString() +",";
            }
            log += "]";
            System.Diagnostics.Debug.WriteLine(log);
            System.Diagnostics.Debug.WriteLine("--------------------------------------");
        }

        private void printMowayList()
        {
            System.Diagnostics.Debug.WriteLine("Moway List:");
            String list = "";
            foreach (Moway moway in mowayList)
            {
                list += " -> "+moway.ToString();
            }
            System.Diagnostics.Debug.WriteLine(list);
            System.Diagnostics.Debug.WriteLine("--------------------------------------");
        }

        private void updateList()
        {
            System.Diagnostics.Debug.WriteLine("-LOG- Cleaning List from not connected Moways... -LOG-");
            long elapsedTicks = 0;
            TimeSpan elapsedSpan;

            for (int i = mowayList.Count - 1; i >= 0; i--)
            {
                elapsedTicks = DateTime.Now.Ticks - mowayList.ElementAt(i).LastComm;
                elapsedSpan = new TimeSpan(elapsedTicks);
                if (elapsedSpan.Seconds > 30)
                {
                    System.Diagnostics.Debug.WriteLine("-LOG- Removing " + mowayList.ElementAt(i).Id + " with " + elapsedSpan.Seconds.ToString() + " -LOG-");
                    mowayList.RemoveAt(i);
                }
            }
        }
    }
}
